package main;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;

import momento.CareTaker;
import momento.Memento;
import actiuni.AddBookmark;
import actiuni.Back;
import actiuni.Command;
import actiuni.Copy;
import actiuni.Cut;
import actiuni.Exit;
import actiuni.Forward;
import actiuni.Help;
import actiuni.NewFile;
import actiuni.NewTab;
import actiuni.OpenFile;
import actiuni.Paste;
import actiuni.Refresh;
import actiuni.SaveFile;
import actiuni.SelectAll;
import actiuni.ShowHistory;
import actiuni.ViewBookmarks;

// TODO: Auto-generated Javadoc
/**
 * The Class Browser.
 */
public class Browser extends JFrame implements HyperlinkListener {
	
	/** The new tab. */
	private Command newTab;
	
	/** The add bookmark. */
	private Command addBookmark;
	
	/** The back button. */
	private Back backButton;
	
	/** The clear history. */
	private Command clearHistory;
	
	/** The copy. */
	private Command copy;
	
	/** The paste. */
	private Command paste;
	
	/** The cut. */
	private Command cut;
	
	/** The exit. */
	private Exit exit;
	
	/** The forward button. */
	private Forward forwardButton;
	
	/** The help. */
	private Help help;
	
	/** The load page. */
	private Command loadPage;
	
	/** The new file. */
	private Command newFile;
	
	/** The open file. */
	private Command openFile;
	
	/** The refresh. */
	private Refresh refresh;
	
	/** The save file. */
	private Command saveFile;
	
	/** The search. */
	private Command search;
	
	/** The select all. */
	private Command selectAll;
	
	/** The show history. */
	private Command showHistory;
	
	/** The stop. */
	private Command stop;
	
	/** The view bookmarks. */
	private Command viewBookmarks;
	
	/** The menu bar. */
	private JMenuBar menuBar;
	
	/** The file menu. */
	private JMenu fileMenu;
	
	/** The file edit. */
	private JMenu fileEdit;
	
	/** The file history. */
	private JMenu fileHistory;
	
	/** The file bookmark. */
	private JMenu fileBookmark;
	
	/** The file help. */
	private JMenu fileHelp;
	
	/** The location text field. */
	public static JTextField locationTextField;
	
	/** The button panel. */
	private JPanel buttonPanel;
	
	/** The display editor pane. */
	public static JEditorPane displayEditorPane;
	
	/** The tp. */
	public static JTabbedPane tp;
	
	/** The singleton browser. */
	private static Browser singletonBrowser;
	
	/** The care taker. */
	private CareTaker careTaker;
	
	/** The title. */
	public static String title;

	/**
	 * Initializare.
	 */
	public void Initializare() {
		careTaker = new CareTaker();
		menuBar = new JMenuBar();
		fileMenu = new JMenu("File");
		fileMenu.setMnemonic(KeyEvent.VK_F);

		// File

		newTab = new NewTab("New Tab");
		newTab.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
				ActionEvent.CTRL_MASK));
		newTab.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				newTab.execute();
			}
		});

		newFile = new NewFile("New Window");
		newFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
				ActionEvent.CTRL_MASK));
		newFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				newFile.execute();
			}
		});

		openFile = new OpenFile("Open File");
		openFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
				ActionEvent.CTRL_MASK));
		openFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openFile.execute();
			}
		});

		saveFile = new SaveFile("Save Page as..");
		saveFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
				ActionEvent.CTRL_MASK));
		saveFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				saveFile.execute();
			}
		});

		exit = new Exit("Exit", KeyEvent.VK_X);
		exit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				exit.execute();
			}
		});

		fileMenu.add((JMenuItem) newTab);
		fileMenu.add((JMenuItem) newFile);
		fileMenu.add((JMenuItem) openFile);
		fileMenu.add((JMenuItem) saveFile);
		fileMenu.add(exit);

		// EDIT

		fileEdit = new JMenu("Edit");
		fileEdit.setMnemonic(KeyEvent.VK_E);

		cut = new Cut("Cut");
		cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
				ActionEvent.CTRL_MASK));
		cut.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				cut.execute();
			}
		});

		copy = new Copy("Copy");
		copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
				ActionEvent.CTRL_MASK));
		copy.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				copy.execute();
			}
		});

		paste = new Paste("Paste");
		paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
				ActionEvent.CTRL_MASK));
		paste.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				paste.execute();
			}
		});

		selectAll = new SelectAll("Select");
		selectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
				ActionEvent.CTRL_MASK));
		selectAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				selectAll.execute();
			}
		});

		fileEdit.add((JMenuItem) cut);
		fileEdit.add((JMenuItem) copy);
		fileEdit.add((JMenuItem) paste);
		fileEdit.add((JMenuItem) selectAll);

		// History

		fileHistory = new JMenu("History");
		fileHistory.setMnemonic(KeyEvent.VK_H);

		showHistory = new ShowHistory("Show All History");
		showHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H,
				ActionEvent.ALT_MASK));
		showHistory.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showHistory.execute();
			}
		});

		clearHistory = new ShowHistory("Clear History");
		clearHistory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,
				ActionEvent.ALT_MASK));
		clearHistory.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				clearHistory.execute();
			}
		});

		fileHistory.add((JMenuItem) showHistory);
		fileHistory.add((JMenuItem) clearHistory);

		// / Bookmark

		fileBookmark = new JMenu("Bookmark");
		fileBookmark.setMnemonic(KeyEvent.VK_B);

		viewBookmarks = new ViewBookmarks("Show All Bookmarks");
		viewBookmarks.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B,
				ActionEvent.ALT_MASK));
		viewBookmarks.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				viewBookmarks.execute();
			}
		});

		addBookmark = new AddBookmark("Bookmark This Page");
		addBookmark.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D,
				ActionEvent.ALT_MASK));
		addBookmark.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addBookmark.execute();
			}
		});

		fileBookmark.add((JMenuItem) viewBookmarks);
		fileBookmark.add((JMenuItem) addBookmark);

		// / Help

		fileHelp = new JMenu("Help");
		fileHelp.setMnemonic(KeyEvent.VK_F);

		help = new Help("About", KeyEvent.VK_F1);
		help.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				help.execute();
			}
		});

		fileHelp.add(help);

		menuBar.add(fileMenu);
		menuBar.add(fileEdit);
		menuBar.add(fileHistory);
		menuBar.add(fileBookmark);
		menuBar.add(fileHelp);

		setJMenuBar(menuBar);

		buttonPanel = new JPanel();
		refresh = new Refresh("R");
		backButton = new Back("<<Go Back");
		backButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionBack();
			}
		});
		refresh.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionBack();
			}
		});

		backButton.setEnabled(false);
		buttonPanel.add(backButton);
		forwardButton = new Forward("Go Forward >>");
		forwardButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionForward();
			}
		});
		forwardButton.setEnabled(false);
		buttonPanel.add(forwardButton);
		locationTextField = new JTextField(35);
		locationTextField.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					actionGo();
				}
			}
		});
		buttonPanel.add(locationTextField);
		JButton goButton = new JButton("Incarca");
		goButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionGo();
			}
		});
		buttonPanel.add(goButton);

		displayEditorPane = new JEditorPane();
		displayEditorPane.setContentType("text/html");
		displayEditorPane.setEditable(false);
		displayEditorPane.addHyperlinkListener(this);
		
		
		tp = new JTabbedPane();
		
		tp.addTab(null, new JScrollPane(displayEditorPane));
		
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add(buttonPanel, BorderLayout.NORTH);
		getContentPane().add(tp, BorderLayout.CENTER);
	}

	/**
	 * Instantiates a new browser.
	 */
	public Browser() {
		super("UVTBrowser");
		Initializare();
		setSize(800, 600);
		/*
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		*/

	}

	/**
	 * Action back.
	 */
	private void actionBack() {
		URL currentUrl = displayEditorPane.getPage();
		try {
			showPage(new URL(careTaker.backMomento().getValue()), false);
		} catch (Exception e) {

		}
	}

	/**
	 * Action forward.
	 */
	private void actionForward() {
		URL currentUrl = displayEditorPane.getPage();
		try {
			showPage(new URL(careTaker.forwardMomento().getValue()), false);
		} catch (Exception e) {
		}
	}

	/**
	 * Action go.
	 */
	private void actionGo() {
		URL verifiedUrl = verifyUrl(locationTextField.getText());
		if (verifiedUrl != null) {
			showPage(verifiedUrl, true);
		} else {
			showError("Invalid URL");
		}
	}

	/**
	 * Show error.
	 *
	 * @param errorMessage the error message
	 */
	private void showError(String errorMessage) {
		JOptionPane.showMessageDialog(this, errorMessage, "Error",
				JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * Verify url.
	 *
	 * @param url the url
	 * @return the url
	 */
	private URL verifyUrl(String url) {
		if (!url.toLowerCase().startsWith("http://"))
			return null;

		URL verifiedUrl = null;
		try {
			verifiedUrl = new URL(url);
		} catch (Exception e) {
			return null;
		}

		return verifiedUrl;
	}

	/**
	 * Show page.
	 *
	 * @param pageUrl the page url
	 * @param addToList the add to list
	 */
	private void showPage(URL pageUrl, boolean addToList) {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

		try {
			displayEditorPane.setPage(pageUrl);
			
			URL newUrl = displayEditorPane.getPage();
			if (!newUrl.toString().equals(pageUrl.toString())) {
				careTaker.addState(new Memento(newUrl.toString()));

			}
			locationTextField.setText(newUrl.toString());
			
			updateButtons();
			
		} catch (Exception e) {
			showError("Unable to load page");
		} finally {
			
			updateTitle();
			setCursor(Cursor.getDefaultCursor());
		}
	}

	/**
	 * Update title.
	 */
	private void updateTitle() {
		HTMLDocument document = (HTMLDocument) displayEditorPane
				.getDocument();
		this.title = (String)  document.getProperty( HTMLDocument.TitleProperty );
		this.setTitle(title);
		
	}

	

	/**
	 * Update buttons.
	 */
	private void updateButtons() {
		if (careTaker.currentIndex() < 1) {
			backButton.setEnabled(false);
			forwardButton.setEnabled(false);
		} else {
			URL currentUrl = displayEditorPane.getPage();
			int pageIndex = careTaker.currentIndex();
			backButton.setEnabled(pageIndex > 0);
			forwardButton.setEnabled(pageIndex < (careTaker.listSize() - 1));
		}
	}

	/* (non-Javadoc)
	 * @see javax.swing.event.HyperlinkListener#hyperlinkUpdate(javax.swing.event.HyperlinkEvent)
	 */
	public void hyperlinkUpdate(HyperlinkEvent event) {
		HyperlinkEvent.EventType eventType = event.getEventType();
		if (eventType == HyperlinkEvent.EventType.ACTIVATED) {
			if (event instanceof HTMLFrameHyperlinkEvent) {
				HTMLFrameHyperlinkEvent linkEvent = (HTMLFrameHyperlinkEvent) event;
				HTMLDocument document = (HTMLDocument) displayEditorPane
						.getDocument();
			
				document.processHTMLFrameHyperlinkEvent(linkEvent);
			} else {
				showPage(event.getURL(), true);
			}
		}
	}

	/**
	 * The main method.
	 *
	 * @param args the arguments
	 */
	public static void main(String[] args) {
		Browser browser = Browser.getInstance();
		browser.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
		browser.show();
	}

	/**
	 * Gets the single instance of Browser.
	 *
	 * @return single instance of Browser
	 */
	public static synchronized Browser getInstance() {
		if (singletonBrowser == null) {
			singletonBrowser = new Browser();
		}
		return singletonBrowser;
	}
	
	
}
